package tech.edwardvan.springsecuritydemo.security.util;

import cn.hutool.json.JSONArray;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.RegisteredPayload;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import tech.edwardvan.springsecuritydemo.security.common.SecurityConstant;
import tech.edwardvan.springsecuritydemo.security.properties.JwtProperties;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * JWT工具类
 *
 * @author EdwardVan
 */
@RequiredArgsConstructor
public class JwtTokenUtil {

    private final JwtProperties jwtProperties;

    public String createToken(UserDetails userDetails) {
        final Date createdDate = new Date();
        final Date expirationDate = new Date(createdDate.getTime() + jwtProperties.getAccessTokenExpireTime() * 60 * 1000);
        return JWT.create()
                .setJWTId("EdwardVan")
                .setSubject(userDetails.getUsername())
                .setIssuedAt(createdDate)
                .setExpiresAt(expirationDate)
                .setKey(jwtProperties.getSecretKey().getBytes())
                .setPayload(SecurityConstant.AUTHORITIES_CLAIMS,
                        userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
                .sign();
    }

    /**
     * 将token转换成UsernamePasswordAuthenticationToken
     */
    public UsernamePasswordAuthenticationToken getAuthentication(String token) {
        JWTPayload payload = parseToken(token).getPayload();
        List<SimpleGrantedAuthority> authorities = getAuthorities(payload);
        String userName = payload.getClaim(RegisteredPayload.SUBJECT).toString();
        return new UsernamePasswordAuthenticationToken(userName, token, authorities);
    }

    /**
     * 将JWTPayload封装成SimpleGrantedAuthority
     */
    private static List<SimpleGrantedAuthority> getAuthorities(JWTPayload jwtPayload) {
        List<String> roleList = ((JSONArray) jwtPayload.getClaim(SecurityConstant.AUTHORITIES_CLAIMS)).toList(String.class);
        return roleList.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

    /**
     * 解析JWT Token
     *
     * @return
     */
    public JWT parseToken(String token) {
        return JWT.of(token);
    }

    /**
     * 验证JWT Token有效性
     */
    public boolean verify(String token) {
        return JWT.of(token).setKey(jwtProperties.getSecretKey().getBytes()).verify();
    }
}